/*
 * XPathExtractor.java is part of htn-core.
 *
 * XPathExtractor.java is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * XPathExtractor.java is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XPathExtractor.java.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.htn.util;

import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.Namespace;

public class XPathExtractor {
	
	private Namespace ns = Namespace.getNamespace("http://www.rtml.org/v3.1a");
	
	public Element getElement(Element node, String xpath) {
		return findSingleElement(node,getXPathElements(xpath));
	}
	
	public Set<Element> getElements(Element node, String xpath) {
		return findMultipleElements(node, getXPathElements(xpath));
	}

	public Attribute getSingleAttribute(Element node, String xpath) {
		String[] xplist = xpath.split("/@");
		Element element = findSingleElement(node,getXPathElements(xplist[0]));
		Attribute att = element.getAttribute(xplist[1]);
		return att;
	}
	
	public Set<Attribute> getMultipleAttributesForElementName(Element node, String xpath) {
		String[] xplist = xpath.split("/@");
		Set<Element> elements = getElements(node,xplist[0]);
		Set<Attribute> atts = new LinkedHashSet<Attribute>();
		for (Element el : elements) {
			atts.add(el.getAttribute(xplist[1]));
		}
		return atts;
	}

	private Element findSingleElement(Element node, Queue<String> xpath) {
		Element element = null;
		if (null != xpath.peek()) {
			String xpelement = xpath.poll();
			Element tmpNode = node.getChild(xpelement,ns);
			if (null != tmpNode && null != tmpNode.getName()) {
				element = findSingleElement(tmpNode,xpath);
			}
		} else {
			element = node;
		}
		return element;
	}
	
	@SuppressWarnings("unchecked")
	private Set<Element> findMultipleElements(Element node, Queue<String> xpath) {
		String lastXPathElement = ((LinkedList<String>)xpath).remove(xpath.size()-1);
		Element penultimate = findSingleElement(node, xpath);
		Set<Element> eset =
			new LinkedHashSet<Element>(
					penultimate.getChildren(lastXPathElement,ns));
		return eset;
	}
	
	private Queue<String> getXPathElements(String xpath) {	
		Queue<String> xpl = new LinkedList<String>();
		for (String el : xpath.split("/")) {
			xpl.offer(el);
		}
		while ("".equals(xpl.peek())) {
			xpl.remove();
		}
		// we remove the first element from the front, since we explicitly
		// require the user to specify the root element.
		xpl.remove();
		return xpl;
	}
	
}
